﻿namespace Known.FreeSql;

class FreeSqlQueryBuilder<T>(FreeSqlDatabase db) : IQueryBuilder<T> where T : class, new()
{
    private readonly FreeSqlDatabase db = db;
    private ISelect<T> query = db.free.Queryable<T>();

    public string WhereSql { get; private set; }
    public Dictionary<string, object> Parameters { get; private set; }

    public IQueryBuilder<TItem> Select<TItem>(Expression<Func<T, TItem>> selector) where TItem : class, new()
    {
        var builder = new FreeSqlQueryBuilder<TItem>(db);
        return builder;
    }

    public IQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
    {
        query = query.Where(predicate);
        return this;
    }

    public IQueryBuilder<T> GroupBy(Expression<Func<T, object>> selector)
    {
        //query = query.GroupBy(selector);
        return this;
    }

    public IQueryBuilder<T> OrderBy(Expression<Func<T, object>> selector)
    {
        query = query.OrderBy(selector);
        return this;
    }

    public IQueryBuilder<T> ThenBy(Expression<Func<T, object>> selector) => OrderBy(selector);

    public IQueryBuilder<T> OrderByDescending(Expression<Func<T, object>> selector)
    {
        query = query.OrderByDescending(selector);
        return this;
    }

    public IQueryBuilder<T> ThenByDescending(Expression<Func<T, object>> selector) => OrderByDescending(selector);

    public async Task<int> CountAsync()
    {
        var count = await query.CountAsync();
        return (int)count;
    }

    public async Task<bool> ExistsAsync()
    {
        var count = await query.CountAsync();
        return count > 0;
    }

    public Task<T> FirstAsync() => FirstAsync<T>();

    public Task<TItem> FirstAsync<TItem>() where TItem : new()
    {
        return query.FirstAsync<TItem>();
    }

    public async Task<TItem> FirstAsync<TItem>(Expression<Func<T, bool>> predicate) where TItem : new()
    {
        var item = await query.FirstAsync(predicate);
        return Utils.MapTo<TItem>(item);
    }

    public Task<List<T>> ToListAsync() => ToListAsync<T>();

    public Task<List<TItem>> ToListAsync<TItem>() where TItem : new()
    {
        return query.ToListAsync<TItem>();
    }

    public async Task<List<TItem>> ToListAsync<TItem>(Expression<Func<T, bool>> predicate) where TItem : new()
    {
        var lists = await query.Where(predicate).ToListAsync();
        return lists?.Select(Utils.MapTo<TItem>).ToList();
    }
}